﻿
using UnityEngine;
using System.Collections.Generic;
using Asgard;
using System.IO;

namespace Asgard
{
    /*
        资源加载回调, 需要检测Obj是否为null
        如果有资源Rebuild的情况, 那么在这里面处理, 例如重新构造Mat, 赋给贴图, 设置Shader等
     */
    public delegate void ResourceLoadFinished(UnityEngine.Object Obj, AssetBundle Bundle, System.Type ObjType, int Flag);


    /*
        场景Assetbundle加载回调, 如果加载成功, SceneBundle为非null
        场景使用完毕后需要手动调用Assetbundle.unload(true)
     */
    public delegate void SceneLoadFinished(SceneBundle SceneBundle, string SceneName);

    public class SceneBundle
    {
        private AssetBundle mBundle = null;
        public SceneBundle(AssetBundle Bundle)
        {
            mBundle = Bundle;
        }
        public void Unload(bool UnloadAll)
        {
            if (mBundle != null)
            {
                mBundle.Unload(UnloadAll);
                mBundle = null;
            }
        }
        public bool IsValid()
        {
            return mBundle != null;
        }
    }

    /**
     *  Assetbundle 加载前提, 与Resouce下的目录保持相同的目录结构
     *  
     *  例如 :                              [Resource/]tanks/10001/10001.fbx
     *          [Application.persistentDataPath/Cache/]tanks/10002/10002.asset
     *          这样可以用统一的方法加载坦克, 不管这个坦克是内置的还是增量更新来的
     * 
     */
    //public class ResourceManager : ISubSystem
    public class ResourceManager
    {
        public static int ASYN_MAX_LOAD_NUM = 2;

        class TaskInfo
        {
            public bool bScene = false;
            public string mName;
            public string mResPath;
            public System.Type mResType;
            public int mFlag;
            public UnityEngine.Object mObj;
            public WWW mWWW;

            public ResourceLoadFinished mResourceCallBack = null;
            public SceneLoadFinished mSceneCallBack = null;
        }

        public void InitData()
        {

        }

        public void DisposeData()
        {

        }
        public void DoFrameUpdate(int time, int delta)
        {
            ProcessResouceLoading();
            ProcessAssetBundle();
        }

        private Queue<TaskInfo> mTasks = new Queue<TaskInfo>();

        /**
            使用异步加载接口, Assetbundle必须为压缩Bundle
         */
        public void LoadResourceAsyn(string ResPath, string Name, System.Type ResType, int Flag, ResourceLoadFinished CallBack)
        {
            TaskInfo NewTask = new TaskInfo();
            NewTask.mName = Name;
            NewTask.mResPath = ResPath;
            NewTask.mResType = ResType;
            NewTask.mResourceCallBack = CallBack;
            NewTask.mFlag = Flag;
            NewTask.bScene = false;
            mTasks.Enqueue(NewTask);
        }

        /**
            使用异步加载接口, Assetbundle必须为压缩Bundle
            场景加载完毕后必须调用SceneBundle.Unload(false)清除Assetbundle资源
         */
        public void LoadSceneAsyn(string ResPath, string Name, SceneLoadFinished CallBack)
        {
            TaskInfo NewTask = new TaskInfo();
            NewTask.mName = Name;
            NewTask.mResPath = ResPath;
            NewTask.mSceneCallBack = CallBack;
            NewTask.mResType = typeof(AssetBundle);
            NewTask.bScene = true;
            mTasks.Enqueue(NewTask);
        }

        /**
            使用同步加载接口, Assetbundle必须为非压缩Bundle
         */
        public void LoadResourceSync(string ResPath, string Name, System.Type ResType, int Flag, ResourceLoadFinished CallBack)
        {
            AssetBundle Bundle = LoadAssetbundleSync(ResPath);
            if (Bundle != null)
            {
                Object Obj = Bundle.Load(Name, ResType);
                if (CallBack != null)
                {
                    CallBack(Obj, Bundle, ResType, Flag);
                }
                Bundle.Unload(false);
            }
            else
            {
                Object Obj = LoadResource(ResPath, ResType);
                if (CallBack != null)
                {
                    CallBack(Obj, null, ResType, Flag);
                }
            }
        }

        /**
            使用同步加载接口, Assetbundle必须为非压缩Bundle
            场景加载完毕后必须调用SceneBundle.Unload(false)清除Assetbundle资源
         */
        public void LoadSceneSync(string ResPath, string Name, SceneLoadFinished CallBack)
        {
            AssetBundle Bundle = LoadAssetbundleSync(ResPath);

            if (CallBack != null)
                CallBack(new SceneBundle(Bundle), Name);
        }

        protected AssetBundle LoadAssetbundleSync(string ResPath)
        {
            string AssetPath = GetAssetBundlePath(ResPath);
            if (System.IO.File.Exists(AssetPath))
            {
                AssetBundle Bundle = AssetBundle.CreateFromFile(AssetPath);
                return Bundle;
            }

            return null;
        }

        public static T LoadResource<T>(string ResPath, bool CheckError = true) where T : UnityEngine.Object
        {
            T Obj = (T)Resources.Load(ResPath, typeof(T));
            if (Obj == null && CheckError)
            {
                Debug.LogError(string.Format("Load Resource [{0}]{1} Failed", typeof(T).ToString(), ResPath));
            }
            return Obj;
        }

        public string GetAssetBundlePath(string ResPath)
        {
            //string AssetPath = string.Format("{0}{1}.asset", PathManager.GetResourceCachePath(), ResPath);
            //return AssetPath;
            string AssetPath = "";
            return AssetPath;
        }

        private UnityEngine.Object LoadResource(string ResPath, System.Type ResType)
        {
            UnityEngine.Object Obj = Resources.Load(ResPath, ResType);
            return Obj;
        }

        private bool DoLoadAssetbundle(TaskInfo CurTask)
        {
            string AssetPath = GetAssetBundlePath(CurTask.mResPath);
            if (File.Exists(AssetPath))
            {
                string WWWPath = string.Format("file:///{0}", AssetPath);
                CurTask.mWWW = new WWW(WWWPath);
                mCurAssetTask = CurTask;

                return true;
            }
            else
            {
                if (CurTask.mSceneCallBack != null)
                {
                    CurTask.mSceneCallBack(new SceneBundle(null), CurTask.mName);
                }
                if (CurTask.mResourceCallBack != null)
                {
                    CurTask.mResourceCallBack(null, null, mCurAssetTask.mResType, mCurAssetTask.mFlag);
                }
                Debug.LogError(string.Format("Load Resource [{0}]{1} Failed", CurTask.mResType.ToString(), CurTask.mResPath));

                return false;
            }
        }

        TaskInfo mCurAssetTask = null;
        private void ProcessResouceLoading()
        {
            if (mTasks.Count > 0 && mCurAssetTask == null)
            {
                TaskInfo CurTask = mTasks.Dequeue();
                if (CurTask.bScene)
                {
                    // 场景资源, 那么必定是Assetbundle
                    DoLoadAssetbundle(CurTask);
                }
                else
                {
                    // 普通资源
                    // 优先加载assetbundle, 如果assetbundle没有才从Resource下加载
                    if (!DoLoadAssetbundle(CurTask))
                    {
                        CurTask.mObj = LoadResource(CurTask.mResPath, CurTask.mResType);
                        if (CurTask.mObj != null)
                        {
                            if (CurTask.mResourceCallBack != null)
                            {
                                CurTask.mResourceCallBack(CurTask.mObj, null, CurTask.mResType, mCurAssetTask.mFlag);
                            }
                        }
                    }
                }
            }
        }

        private void ClearAssetTask(bool UnloadBundle)
        {
            mCurAssetTask.mObj = null;
            if (mCurAssetTask.mWWW != null)
            {
                if (UnloadBundle && mCurAssetTask.mWWW.assetBundle != null)
                    mCurAssetTask.mWWW.assetBundle.Unload(false);

                mCurAssetTask.mWWW.Dispose();
                mCurAssetTask.mWWW = null;
            }
            mCurAssetTask = null;
        }

        private void ProcessAssetBundle()
        {
            if (mCurAssetTask != null)
            {
                WWW CurWWW = mCurAssetTask.mWWW;
                if (!string.IsNullOrEmpty(mCurAssetTask.mWWW.error))
                {
                    Debug.LogError(string.Format("Load Resource [{0}]{1} Failed", mCurAssetTask.mResType.ToString(), mCurAssetTask.mResPath));
                    if (mCurAssetTask.mResourceCallBack != null)
                    {
                        mCurAssetTask.mResourceCallBack(null, null, mCurAssetTask.mResType, mCurAssetTask.mFlag);
                    }

                    ClearAssetTask(false);
                    return;
                }

                if (CurWWW.isDone)
                {
                    AssetBundle Bundle = CurWWW.assetBundle;
                    if (mCurAssetTask.bScene)
                    {
                        if (mCurAssetTask.mSceneCallBack != null)
                        {
                            mCurAssetTask.mSceneCallBack(new SceneBundle(Bundle), mCurAssetTask.mName);
                        };

                        ClearAssetTask(false);
                    }
                    else
                    {
                        mCurAssetTask.mObj = Bundle.Load(mCurAssetTask.mName, mCurAssetTask.mResType);

                        if (mCurAssetTask.mObj == null)
                        {
                            Debug.LogError(string.Format("Load Resource [{0}]{1} Failed", mCurAssetTask.mResType.ToString(), mCurAssetTask.mResPath));
                        }

                        if (mCurAssetTask.mResourceCallBack != null)
                        {
                            mCurAssetTask.mResourceCallBack(mCurAssetTask.mObj, Bundle, mCurAssetTask.mResType, mCurAssetTask.mFlag);
                        }

                        ClearAssetTask(true);
                    }
                }
            }
        }
    }
}